// 声明合并 如果定义了两个相同名字的函数、接口或类，那么它们会合并成一个类型：
{
    // 函数的合并 --> 函数的重载
    function say(a: number,d:symbol): number;
    function say(b: string): string;
    function say(c:number | string):any {
        typeof c === 'number' ? console.log('520'+c) : console.log('250'+c);
    }
    say(520,Symbol(12))
    say('LiuNan')
}

{
    // 接口的合并
    interface Add {
        name:string
    }

    interface Add {
        // name:number; // 如果出现相同的属性声明时，定义的类型必须保持一致
        age:number;
    }

    // 上面的接口合并后就是这样的
    interface AddMerge {
        name:string;
        age:number;
    }

    let obj:Add = {
        name:'wm',
        age:22
    }
    console.log(obj)
}

{
    // 接口中方法如果是以函数定义的方式那么属性与方法的合并都表现一致，如果是定义函数的接口那么构造函数的合并与函数的合并表现一致
    interface Add {
        work:string;
        sayHello:(a:number) => number;
        (x:number,y:string):boolean;
    }

    interface Add {
        age:number;
        sayHello:(a:number) => number; // 当函数定义为方法的时候，如果出现相同的声明时，定义的参数和返回类型必须保持一致，跟普通的属性合并一样
        (x:string):string // 当函数定义为构造函数时，遇到相同声明时，会使用函数重载的方式进行合并，运行有不同的参数和返回类型
    }
    // 合并后的形式如下
    interface AddMerge {
        work:string;
        age:number;
        sayHello:(a:number) => string;
        (x:string|number):string|number
    }

    let add:Add = (function (x:string|number,y?:string) {
        return x
    }) as Add
    add.work = 'wm';
    add.age = 22;
    add.sayHello = function (b) {
        return b
    }
    console.log(add('whmk'))
}

{
    // 接口中方法如果是以函数声明的方式，那么方法的合并与函数的合并表现一致
    interface Alarm {
        price: number;
        alert(s: string): string;
    }
    interface Alarm {
        weight: number;
        alert(s: string, n: number): string;
    }
    // 合并后的形式如下
    interface AlarmMerge {
        weight:number;
        price:number;
        alert(s: string, n: number): string;  // 注意每组接口里的声明顺序保持不变，但各组接口之间的顺序是：后来的接口重载时出现在靠前位置。
        alert(s: string): string;
    }
    let  alarm:Alarm = {
        price:180,
        weight:200,
        alert(s:string,n?:number): string { // 注意这里n是可选参数，因为第一个接口声明时没有n这个参数
            return n?String(n) + s:s
        }
    }
    console.log(alarm.alert('whmk',520))
}

// 这个规则有一个例外是当出现特殊的函数签名时。 如果签名里有一个参数的类型是 单一的字符串字面量（比如，不是字符串字面量的联合类型），那么它将会被提升到重载列表的最顶端。
// 前面的数字是正常情况下的排序，后面由于某个函数提升后改变的顺序
{
    interface Alarm {
        alert(s:string,n:'big'):string //5=> 2
    }

    interface Alarm {
        alert(s:number):number //3=> 4
        alert(s:string):string //4=> 5
    }

    interface Alarm {
        alert(s:boolean):boolean //1=> 3
        alert(s:'egg',n:number):number[] //2=> 1
    }

    // 函数声明合并后的顺序
    interface AlarmMerge {
        alert(s:'egg',n:number):number[]
        alert(s:string,n:'big'):string
        alert(s:boolean):boolean
        alert(s:number):number
        alert(s:string):string
    }

    // 具体实现
    let a:Alarm = {
        alert(s:any,n?:any): any {
            return s + n
        }
    }

    console.log(a.alert('egg',109))
}

//命名空间与类、函数、枚举类型的合并
/*
{
   class Album {
    public label:Album.AlbumLabel = 'hello world!'
}

namespace Album {
    export type AlbumLabel = string
    const age = 100
    export function sayHello(str:string):void {
        console.log(str)
    }
}

var a:Album = new Album()

Album.sayHello(a.label)
}*/

//命名空间与函数的合并
/*{
    function f() {
        return f.name + f.age + f.grade;
    }

    // 为函数增加来一些属性
    namespace f {
        export let age = 22
        export let grade = 100
        let work = 'swim'
    }

    console.log(f())
}*/

// 命名空间与枚举类型的合并
/*{
    enum Color {
        yellow,
        green,
        blue
    }

    namespace Color {
        export function sayHello() {
            console.log('hello Color!',Color)
        }
    }

    Color.sayHello()
}*/

